// HSS.Forms.Docking.DockPaneStripBase.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       DockPaneStripBase.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Security.Permissions;
using System.Windows.Forms;

namespace HSS.Forms.Docking
{
	#region DockPaneStripBase
	/// <summary>
	/// DockPaneStripBase
	/// </summary>
	public abstract class DockPaneStripBase : Control
	{
		#region Tab
		/// <summary>
		/// Tab
		/// </summary>
		[SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
		protected internal class Tab : IDisposable
		{
			IDockContent _content;

			#region Constructor
			/// <summary>
			/// ctor
			/// </summary>
			/// <param name="content">IDockContent</param>
			public Tab(IDockContent content)
			{
				_content = content;
			}
			/// <summary>
			/// Finalzier
			/// </summary>
			~Tab()
			{
				Dispose(false);
			}
			#endregion

			/// <summary>
			/// Content
			/// </summary>
			public IDockContent Content
			{
				get { return _content; }
			}
			/// <summary>
			/// ContentForm
			/// </summary>
			public Form ContentForm
			{
				get { return _content as Form; }
			}
			/// <summary>
			/// Dispose
			/// </summary>
			public void Dispose()
			{
				Dispose(true);
				GC.SuppressFinalize(this);
			}
			/// <summary>
			/// Dispose
			/// </summary>
			/// <param name="disposing">bool</param>
			protected virtual void Dispose(bool disposing)
			{
			}
		}
		#endregion

		#region TabCollection
		/// <summary>
		/// TabCollection
		/// </summary>
		[SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
		protected sealed class TabCollection : IEnumerable<Tab>
		{
			#region IEnumerable Members
			IEnumerator<Tab> IEnumerable<Tab>.GetEnumerator()
			{
				for (int i = 0; i < Count; i++)
					yield return this[i];
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				for (int i = 0; i < Count; i++)
					yield return this[i];
			}
			#endregion

			#region Constructor
			/// <summary>
			/// ctor
			/// </summary>
			/// <param name="pane">DockPane</param>
			internal TabCollection(DockPane pane)
			{
				_dockPane = pane;
			}
			#endregion

			/// <summary>
			/// DockPane
			/// </summary>
			public DockPane DockPane
			{
				get { return _dockPane; }
			} DockPane _dockPane;
			/// <summary>
			/// Count
			/// </summary>
			public int Count
			{
				get { return DockPane.DisplayingContents.Count; }
			}
			/// <summary>
			/// Indexer
			/// </summary>
			/// <param name="index">Index</param>
			/// <returns>Tab</returns>
			public Tab this[int index]
			{
				get
				{
					IDockContent content = DockPane.DisplayingContents[index];
					if (content == null)
						throw (new ArgumentOutOfRangeException("index"));
					return content.DockHandler.GetTab(DockPane.TabStripControl);
				}
			}
			/// <summary>
			/// Contains
			/// </summary>
			/// <param name="tab">Tab</param>
			/// <returns>bool</returns>
			public bool Contains(Tab tab)
			{
				return (IndexOf(tab) != -1);
			}
			/// <summary>
			/// Contains
			/// </summary>
			/// <param name="content">IDockContent</param>
			/// <returns>bool</returns>
			public bool Contains(IDockContent content)
			{
				return (IndexOf(content) != -1);
			}
			/// <summary>
			/// IndexOf
			/// </summary>
			/// <param name="tab">Tab</param>
			/// <returns>index</returns>
			public int IndexOf(Tab tab)
			{
				if (tab == null)
					return -1;

				return DockPane.DisplayingContents.IndexOf(tab.Content);
			}
			/// <summary>
			/// IndexOf
			/// </summary>
			/// <param name="content">IDockContent</param>
			/// <returns>index</returns>
			public int IndexOf(IDockContent content)
			{
				return DockPane.DisplayingContents.IndexOf(content);
			}
		}
		#endregion

		/// <summary>
		/// DockPaneStripBase
		/// </summary>
		/// <param name="pane">DockPane</param>
		protected DockPaneStripBase(DockPane pane)
		{
			_dockPane = pane;

			SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
			SetStyle(ControlStyles.Selectable, false);
			AllowDrop = true;
		}

		/// <summary>
		/// DockPane
		/// </summary>
		protected DockPane DockPane
		{
			get { return _dockPane; }
		} DockPane _dockPane;

		/// <summary>
		/// Appearance
		/// </summary>
		protected DockPane.AppearanceStyle Appearance
		{
			get { return DockPane.Appearance; }
		}

		/// <summary>
		/// Tabs
		/// </summary>
		protected TabCollection Tabs
		{
			get
			{
				if (_tabs == null)
					_tabs = new TabCollection(DockPane);

				return _tabs;
			}
		} TabCollection _tabs = null;

		/// <summary>
		/// OnRefreshChanges
		/// </summary>
		protected virtual void OnRefreshChanges()
		{
		}

		/// <summary>
		/// MeasureHeight
		/// </summary>
		/// <returns>int</returns>
		protected internal abstract int MeasureHeight();

		/// <summary>
		/// EnsureTabVisible
		/// </summary>
		/// <param name="content">IDockContent</param>
		protected internal abstract void EnsureTabVisible(IDockContent content);

		/// <summary>
		/// HitTest
		/// </summary>
		/// <returns>int</returns>
		protected int HitTest()
		{
			return HitTest(PointToClient(Control.MousePosition));
		}

		/// <summary>
		/// HitTest
		/// </summary>
		/// <param name="point">Point</param>
		/// <returns>int</returns>
		protected internal abstract int HitTest(Point point);

		/// <summary>
		/// GetOutline
		/// </summary>
		/// <param name="index">int</param>
		/// <returns>GraphicsPath</returns>
		protected internal abstract GraphicsPath GetOutline(int index);

		/// <summary>
		/// CreateTab
		/// </summary>
		/// <param name="content">IDockContent</param>
		/// <returns>HasTabPageContextMenu</returns>
		protected internal virtual Tab CreateTab(IDockContent content)
		{
			return new Tab(content);
		}

		/// <summary>
		/// OnMouseDown
		/// </summary>
		/// <param name="e">MouseEventArgs</param>
		protected override void OnMouseDown(MouseEventArgs e)
		{
			base.OnMouseDown(e);

			int index = HitTest();
			if (index != -1)
			{
				IDockContent content = Tabs[index].Content;
				if (DockPane.ActiveContent != content)
					DockPane.ActiveContent = content;
			}

			if (e.Button == MouseButtons.Left)
			{
				if (DockPane.DockPanel.AllowEndUserDocking && DockPane.AllowDockDragAndDrop && DockPane.ActiveContent.DockHandler.AllowEndUserDocking)
					DockPane.DockPanel.BeginDrag(DockPane.ActiveContent.DockHandler);
			}
		}

		/// <summary>
		/// HasTabPageContextMenu
		/// </summary>
		protected bool HasTabPageContextMenu
		{
			get { return DockPane.HasTabPageContextMenu; }
		}

		/// <summary>
		/// //ShowTabPageContextMenu
		/// </summary>
		/// <param name="position">Point</param>
		protected void ShowTabPageContextMenu(Point position)
		{
			DockPane.ShowTabPageContextMenu(this, position);
		}

		/// <summary>
		/// OnMouseUp
		/// </summary>
		/// <param name="e">MouseEventArgs</param>
		protected override void OnMouseUp(MouseEventArgs e)
		{
			base.OnMouseUp(e);

			if (e.Button == MouseButtons.Right)
				ShowTabPageContextMenu(new Point(e.X, e.Y));
		}

		/// <summary>
		/// WndProc
		/// </summary>
		/// <param name="m">Message</param>
		[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
		protected override void WndProc(ref Message m)
		{
			if (m.Msg == (int)Msgs.WM_LBUTTONDBLCLK)
			{
				base.WndProc(ref m);

				int index = HitTest();
				if (DockPane.DockPanel.AllowEndUserDocking && index != -1)
				{
					IDockContent content = Tabs[index].Content;
					if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown)
						content.DockHandler.IsFloat = !content.DockHandler.IsFloat;
				}

				return;
			}

			base.WndProc(ref m);
			return;
		}

		/// <summary>
		/// //
		/// </summary>
		/// <param name="drgevent"></param>
		protected override void OnDragOver(DragEventArgs drgevent)
		{
			base.OnDragOver(drgevent);

			int index = HitTest();
			if (index != -1)
			{
				IDockContent content = Tabs[index].Content;
				if (DockPane.ActiveContent != content)
					DockPane.ActiveContent = content;
			}
		}

		internal void RefreshChanges()
		{
			if (IsDisposed)
				return;

			OnRefreshChanges();
		}

	}
	#endregion
}